package moreHealthControl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.Properties;
import java.util.Scanner;

import moreHealthException.IntTextFieldException;
import moreHealthException.StringLengthException;
import moreHealthModel.Campus.CampusLocation;
import moreHealthModel.Campus.FoodSources.FastFood;
import moreHealthModel.Campus.FoodSources.Restaurant;
import moreHealthModel.Campus.LearningEnvironment.ClassRoom;
import moreHealthModel.Campus.LearningEnvironment.Library;
import moreHealthModel.Campus.Residences.Residence1;
import moreHealthModel.Campus.Transit.Halls;
import moreHealthModel.Campus.Transit.Sidewalk;
import moreHealthModel.Student.Student;
import moreHealthModel.Student.StudentJourney;
import moreHealthModel.Student.Student.Disease;
import moreHealthView.StudentJourneyGrid;
import moreHealthView.StudentInformationForm.MonthCode;


//Contains all the operation to be performed on the Student Entered Information.
//Currently there are: 	1.	Display the Seriousness factor based on the Student Information entered.
//						2.	Get the Student journey Information and display on the grid.  
public class StudentJourneyProcessor
	{
	
		//ATTRIBUTES ======================================
		
		//the student for whom Health related facts are being determined. 
		Student s;	
		
		//The information entered by the User about the Student in the Form. 
		private HashMap<String, Object> studentInputDatax_;
		
		//This is set to false which indicates that something horrible happened while entering the Student data.
		boolean successStatusx_= false;
		
		//Student Information
		String firstNamex_ = "";
		String lastNamex_ = "";
		//int agex_ = 0;
		int weightx_ = 0;
		int heightx_ = 0;
		Disease diseaseNamex_;
		String radioDobMonthx_ = "";
		int yearTextFieldx_ = 0;
		
		
		//DEFAULT CONSTRUCTORS ======================================
		public StudentJourneyProcessor(){
			
		}
		
		
		//CONSTRUCTORS ======================================
		//INTENT: Stores the student data entered by the user. 
		//PRE-CONDITION : 
			//1. There has to be complete data. 
		//POST-CONDITION: 
			// 
		public StudentJourneyProcessor(HashMap<String, Object> studentInputData){
			this.studentInputDatax_ = studentInputData;
		}
		
		
		//INTENT: Calculate the Student seriousness factor for the student as per the data entered. 
		//PRE-CONDITION	:
			//1. Student data should be present i.e. Name, Age, Height, Weight. 
			//2. 
		//POST-CONDITION:
			//1. Display student Information and the the Seriousness factor. 
			//2. If no data is enter prompt user to go to Read Me for instruction or else use the default value.
		public void configureStudentObject(){

			 
			 if (studentInputDatax_.isEmpty()){
				 System.out.println("Please enter Information. Check Read me for instructions");
					
			 }
			 
			 else {
				 
				 try{
					 
					 //Information entered for the student. 	
			 firstNamex_ = (String) studentInputDatax_.get("firstName");
			 lastNamex_ =	(String) studentInputDatax_.get("lastName");
			 diseaseNamex_ = (Disease) studentInputDatax_.get("disease");
			 weightx_ = Integer.parseInt((String) studentInputDatax_.get("weight"));
			 heightx_  = Integer.parseInt((String) studentInputDatax_.get("height"));
			 radioDobMonthx_ = (String) studentInputDatax_.get("dobmonth");
			 yearTextFieldx_ = Integer.parseInt((String) studentInputDatax_.get("dobyear"));
			 
			 
			 
			 //Get the age of the Student.
			 int studentAge = CalculateStudentAge (radioDobMonthx_, yearTextFieldx_);
			 
			 
			 
			 //The student for whom we are calculating the seriousness factor. 
			 s = new Student(firstNamex_ + " " + lastNamex_, studentAge, heightx_, weightx_, diseaseNamex_);
			
			 
			 //Display the results if the data entered for the student is right and conforms with the programming constraints. 
			 if (s!=null)
				 {
				System.out.println("Student Name: " + s.GetName());
				System.out.println("Student Age: " + s.GetAge());
				System.out.println("Student Weight: " + s.GetWeight());
				System.out.println("Student Height: " + s.GetHeight());
				System.out.println("Student Seriousness Metric: " + s.CalcSeriousnessFactor(s));
				successStatusx_ = true;
				 } else {//Data entered is not right. 
					 setErrorMessage();
				 }
			 }
			 
				 //happens when Age, Height, or Weight have string. 
			 catch (NumberFormatException nan){
				 try
					{
					throw new IntTextFieldException("0", "Ooops!!! I think that some text field can only " +
							"take integers like age, weight and height");
					} catch (IntTextFieldException e)
					{

						System.out.println(e.getReturnErrorMessage());
					}
				 nan.printStackTrace();
				}

			}
		}
		
		
		//INTENT: To Indicate that the operation did not complete as assumed. 
		//PRE-CONDITION:
			//1.	By default set to false that is unsuccessful. 
		//Post-CONDITION: 
			//1.	Indicates that the operation was a success or not. 
		public boolean getSuccessStatus(){
			return successStatusx_;
		}
		
		
		//INTENT: To show user that one of the data entered is wrong. 
		//PRE-CONDITION: none
		//POST-CONDITION:
			//1. Display the error message and change the success to false ie. something went wrong during the operation.
		public void setErrorMessage (){
			System.out.println("One or more data entered is incorrect. Please refer the ReadMe.txt for Instruction.");
			successStatusx_ = false;
		}
				
		
		//INTENT: Lets the user enter his travel information for the day. 
		//PRE-CONDITION	: 
			//1.	The latitude and longitude has to be  integer and less than the scale for the campus Map.
			//2.	The time has to be integer.
			//3.	If you want to add more location then answer the Question with only Y(y) or N(n)
			//4.	The latitude and longitude the user has added should match with that in the Map. i.e. 
			//		If (0,1) is a Hall according to the student then it should be a Hall in the Map. 
			//		If this is not the case then that cell in the grid will display a error message. 
		//POST-CONDITION:
			//1. Gets the location the student been and add those location in order to be displayed on the map. 
		public void getStudentJourneyCals(){
			
			try{
				
			//The student whose journey we need to display in the map
			StudentJourney studjrny1 = new StudentJourney();
			studjrny1.setStudentInfo(s);
			
			//True If the user wants to add more location to his list. 
			boolean ans=true;
			while (ans==true)
				{
			
			Scanner in = new Scanner(System.in);
			
			//Set and Get the latitude and longitude and the time. 
			System.out.println("Please Enter Longitude : ");
			int longitude = in.nextInt();
			
			//The longitude cannot be greater than the grid scale 
			if (longitude>= studjrny1.getScale()){
			throw new StringLengthException("Latitude should be less " + studjrny1.getScale());
			}
			
			
			System.out.println("Please Enter Latitude : ");
			int latitude = in.nextInt();
			
			
			//The latitude cannot be greater than the grid scale
			if(latitude>= studjrny1.getScale()){
				throw new StringLengthException("Latitude should be less " + studjrny1.getScale());
			}
			
			System.out.println("Please Enter time : ");
			int time = in.nextInt();
			
			//Different type of location the person can go to. 
			System.out.println("Please choose the Location Type from the list: 1.Hall 2.Side-Walk 3.Fast-Food 4.Restaurants 5.Residences 6.Library 7.Classrooms");
			int locCode = in.nextInt();
			String locType="";
			
			switch(locCode)
						{
					case 1:
						locType = "hall";
						break;
					case 2:
						locType ="sidewalk";
						break;
					case 3:
						locType ="fastfood";
						break;
					case 4:
						locType ="restaurant";
						break;
					case 5:
						locType ="residences";
						break;
					case 6:
						locType ="Library";
						break;
					case 7:
						locType ="ClassRoom";
						break;
					default: 
						throw new StringLengthException("Please select one of the above options");
						}

			//Sets the the Locations where the Student has been to. 
			locationType(latitude,longitude,time,locType,studjrny1);
			
			
			//Add logic to get the nearby POI.
			StudentJrnyPatternLookUp displayLocationOfInterest = new StudentJrnyPatternLookUp();	
			//displayLocationOfInterest.getCurrentStudentLocation(studjrny1.getStudentVisitedPlaces());
			
			
			System.out.println("Did you travel any where else? Select Y/N: ");
			String res= in.next();
			if (res.equals("N") || res.equals("n")){
				ans=false;
				}
			
			else if (res.equals("Y") || res.equals("y")){
				ans = true;
			}
			else{
				
				//User entered did not enter letter than y(y) or N(n)
				throw new StringLengthException(res + " is an invalid input.");
			}
			}
			
			//Calculate the total distance traveled Student in a day. 
			System.out.println("Total Distance travelled is: "+ studjrny1.TotalDistanceCalculator(studjrny1.getStudentVisitedPlaces()));
			
			//Display on the map where the student has been to and the time he was there. 
			//It will return true and print "Map constructed" if the map was configured properly or else else false and print "Map not constructed."
			if (ConstructMapStudentJourney(studjrny1.getStudentVisitedPlaces())){
			System.out.println("Map Constructed is correct");
			}
			else {
				System.out.println("Map constructed is not correct.");
			}
		}
			
			//If a string was input for latitude or longitude instead of an integer.
			catch (NumberFormatException e){
				try {
					throw new IntTextFieldException("0", "The value is not integer.");
				} catch (IntTextFieldException e1) {
					// TODO Auto-generated catch block
					System.out.println(e1.getReturnErrorMessage());
				}
			}
			
			// Happens when the student select a location option not available on the screen.
			catch (StringLengthException invalidLocationType){
				System.out.println(invalidLocationType.getReturnDefaultValue());
			}
			
			//happens when expected input is integer but got string. For example Latitude and longitude are always ints.
			catch(InputMismatchException consoleInput){
				System.out.println("One more console inputs need to be an integer.");
			}
			
			 catch (IOException e) {
						e.printStackTrace();
					}
			 
		}
		
		
				
		//INTENT: Different location the Student can visit. This location information will be used to process Student Journey on the Campus Map.
		//PRE-CONDITION	:
			//1.	The location has to represented for a Student. 
			//2.	The latitude, longitude and time have to be position
		//POST-CONDITION:
			//1.	Add the location the student has been for displaying it on the map. 
		public static void locationType(int longitude, int latitude, int time, String locationType, StudentJourney stdJrn) throws IOException
		
		{
			BufferedReader br1 = new BufferedReader(new InputStreamReader(System.in));
			
			if (locationType.equals("hall"))
				{
					System.out.println("Enter the Hall Address. If there is none leave it blank");
					String halladdrs= br1.readLine();
					stdJrn.setStudentVisitedPlaces(new Halls(latitude, longitude, halladdrs, time));
				}
			
			else if (locationType.equals("sidewalk"))
				{
					stdJrn.setStudentVisitedPlaces(new Sidewalk(latitude, longitude, time));
				}
			else if (locationType.equals("fastfood"))
				{
					System.out.println("Enter the Fast Food Address. If there is none leave it blank");
					String fastfoodaddrs= br1.readLine();
					stdJrn.setStudentVisitedPlaces(new FastFood(latitude, longitude, fastfoodaddrs, time));
				}
			else if (locationType.equals("restaurant"))
				{
					System.out.println("Enter the Restaurant Address. If there is none leave it blank");
					String restaddrs= br1.readLine();
					stdJrn.setStudentVisitedPlaces(new Restaurant(latitude, longitude, restaddrs, time));
				}
			else if (locationType.equals("residences"))
				{
					System.out.println("Enter the Residences Address. If there is none leave it blank");
					String res1addrs= br1.readLine();
					stdJrn.setStudentVisitedPlaces(new Residence1(latitude, longitude, res1addrs, time));
				}
			else if (locationType.equals("Library"))
				{
					System.out.println("Enter the Library Address. If there is none leave it blank");
					String libaddrs= br1.readLine();
					stdJrn.setStudentVisitedPlaces(new Library(latitude, longitude, libaddrs, time));
				}
			else if (locationType.equals("ClassRoom"))
				{
					System.out.println("Enter the ClassRoom Address. If there is none leave it blank");
					String classaddrs= br1.readLine();
					stdJrn.setStudentVisitedPlaces(new ClassRoom(latitude, longitude, classaddrs, time));
				}
			 
		}
		
		
		
		//INTENT: Add the data of where the Student has been to the map. 
		//PRE-CONDITION	:none
		//POST-CONDITION:
			//1.Displays the map with the student journey information. 	
		public boolean ConstructMapStudentJourney(ArrayList<CampusLocation> studentJourneyInfo) throws IOException
		
		{	
			//Get each Location Information the Student has been to. 
			StudentJourneyGrid sj = new StudentJourneyGrid(studentJourneyInfo);
			 return sj.getgridDisplaySuccess();


		}
	
		
		//INTENT		:	Using the Student DOB Info from the form calculate the DOB of the student.  
		//PRE-CONDITION	:	
			//	1.	DobMonth cannot be null
			//	2.	Year should always be integer and 0 or more. 
		//POST-CONDITION:	
			//	1.	Calculate the age of the Student in terms of years. 
			//	2.	If calculation is not successful then set the Default value to 0. 
	public int CalculateStudentAge(String studentDobMonth, int studentDobYear){
	
		int diffOfYears= 0;
		try{
			
		
		MonthCode mb = null;
		
		if (studentDobMonth.equals("Jan")){
			mb = MonthCode.Jan;
		} else if(studentDobMonth.equals("Feb")){
			mb = MonthCode.Feb;
		}
		 else if(studentDobMonth.equals("Mar")){
			 mb = MonthCode.Mar;
		}
		else if(studentDobMonth.equals("Apr")){
			mb = MonthCode.Apr;
		}
		 else if(studentDobMonth.equals("May")){
			 mb = MonthCode.May;
		}
		 else if(studentDobMonth.equals("Jun")){
			 mb = MonthCode.Jun;
		}
		 else if(studentDobMonth.equals("Jul")){
			 mb = MonthCode.Jul;
		}
		 else if(studentDobMonth.equals("Aug")){
			 mb = MonthCode.Aug;
		}
		 else if(studentDobMonth.equals("Sep")){
			 mb = MonthCode.Sep;
		}
		 else if(studentDobMonth.equals("Oct")){
			 mb = MonthCode.Oct;
		}
		 else if(studentDobMonth.equals("Nov")){
			 mb = MonthCode.Nov;
		}
		 else if(studentDobMonth.equals("Dec")){
			 mb = MonthCode.Dec;
		}
		 else{
			 
			 mb= MonthCode.Invalid;
		 }

		int monthCode = mb.GetMonthCode();
		
		Calendar currentDate = Calendar.getInstance();
		Calendar studentDate = Calendar.getInstance();
		studentDate.set(studentDobYear, monthCode, 1);
		

        // Get date in milliseconds
        long milisecondCurrentDate = currentDate.getTimeInMillis();
        long milisecondStudentDate = studentDate.getTimeInMillis();

        // Find date difference in milliseconds
        long diffInMSec = milisecondCurrentDate - milisecondStudentDate;

        // Find date difference in years 
        // (24 hours 60 minutes 60 seconds 1000 millisecond)
        diffOfYears = (int) ((diffInMSec / (24 * 60 * 60 * 1000))/365);

        System.out.println("Date Difference in : " + diffOfYears + " years.");
 
        if (diffOfYears<0){
        	try {
				throw new IntTextFieldException("0", "Age not set successfully. Settin default value 0.");
			} catch (IntTextFieldException e) {
				diffOfYears = Integer.parseInt(e.getReturnDefaultValue());
				System.out.println(e.getReturnErrorMessage());
				
			}
        }

	} catch(NullPointerException np){
		diffOfYears = 0;
	}
	return diffOfYears;
	}
	
}
